React hook form(4) - controlled component & forwardRef


Posted by TempuraEngineer on 2023-08-20

目錄


在前幾篇有提到Controller + control可以幫助你把包裝得很深的組件和react hook form做連結

那是否有Controller + control以外的方法呢🤔

這或許要先了解一下react hook form的一大重點uncontrolled component

而當表單內的欄位是uncontrolled component時,會需要透過ref來操作DOM,進而控制表單


ref

在React18,ref分為幾種,通常被用在你想要組件記得一些資料,但是又不想要每次資料更新時組件都會re-render時

  • callback ref
    組件掛載好後,React會呼叫它,然後取得DOM元素(不需要selector)
    react-hook-form的register回傳的ref就是這種
  • ref object
    使用createRef、useRef可以建立ref物件,使用ref.current可以取得值
    兩者的差異在於前者被呼叫會回傳一個新的物件(reference不同),後者則是每次渲染都回傳同個物件(reference一樣)
  • forwardRef
    forwardRef是接收functional component的function,透過它可以將子組件的ref暴露給父組件
    常見於深度包裝的組件或HOC


包裝很深的組件怎麼註冊

一些包裝得很深的組件(ex: MUI的組件,或者自己做的組件)配合react-hook-form使用時,可能會遇到明明畫面上顯示的值改變了,但實際上form的值沒有改變的問題,這是因為沒有成功把register回傳值傳給組件

根據官方文件,只要正確地暴露ref給上層組件,就能運作

Props Name: ref
Type: React.Ref
Description: Input reference for hook form to register.

所以要做的就是將組件用forwardRef包起來

const Select = forwardRef(
  <T extends string>(
    { label, children, ...resetProps }: MuiSelectProps<T>,
    ref: ForwardedRef<HTMLInputElement>
  ) => {
    return (
      <>
        <InputLabel shrink style={{ textAlign: "left" }}>
          {label}
        </InputLabel>
        <MuiSelect ref={ref} {...resetProps}>
          {children}
        </MuiSelect>
      </>
    );
  }
);

用起來則會像這樣

<Select
        label="Education"
        displayEmpty
        renderValue={(selected) => {
          return <Typography>{selected}</Typography>;
        }}
        {...register("highestEducation")}
      >
        {educationOptions.map(({ label, value }) => (
          <MenuItem value={value} key={value} style={{ textAlign: "left" }}>
            {label}
          </MenuItem>
        ))}
      </Select>


參考資料

forwardRef
Referencing Values with Refs
A complete guide to React refs
Things you need to know about React ref
React hook form - register


#react-hook-form #forwardRef #controlled component







Related Posts

TypeScript 筆記:原始型別

TypeScript 筆記:原始型別

Chucker --- View the interaction between the app and the api

Chucker --- View the interaction between the app and the api

content-length mismatch composer laravel

content-length mismatch composer laravel


Comments